package com.uxsino.commons.utils;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class SubnetUtil {

    private static Logger logger = LoggerFactory.getLogger(SubnetUtil.class);

    private int[] ipPart;

    private int subnetMask;

    private int[] startIP;

    private int[] endIP;

    public SubnetUtil(String ip, int subnet) throws IllegalArgumentException {
        ipPart = new int[4];
        String[] ipArr = ip.split("\\.");
        if (ipArr.length != 4) {
            logger.error("ip:{} format is illegal", ip);
            throw new IllegalArgumentException("IP is not in format of xxx.xxx.xxx.xxx");
        }
        for (int i = 0; i < ipPart.length; i++) {
            try {
                ipPart[i] = Integer.parseInt(ipArr[i]);
                if (ipPart[i] < 0 || ipPart[i] > 255) {
                    logger.error("ip part is out of range [0-255]");
                    throw new IllegalArgumentException("ip part is out of range [0-255]");
                }
            } catch (NumberFormatException e) {
                logger.error("ip {} part {} cannot parse to int", ip, ipArr[i]);
                throw new IllegalArgumentException("part of ip is not integer");
            }
        }

        if (subnet < 0 || subnet > 32) {
            logger.error("subnet {} is out of range [0-32]", subnet);
            throw new IllegalArgumentException("subnet is out of range [0-32]");
        }
        this.subnetMask = subnet;
        startIP = new int[4];
        endIP = new int[4];

        calculateSubnet();
    }

    private void calculateSubnet() {
        int startIndex = subnetMask / 8 + (subnetMask % 8 == 0 ? -1 : 0);   // range:[-1,3]
        if (startIndex == -1) {
            for (int i = 0; i < startIP.length; i++) {
                startIP[i] = 0;
                endIP[i] = 255;
            }
            return;
        }
        int partCount = subnetMask % 8 == 0 ? (1 << 8) : (1 << (subnetMask % 8));
        int eachPart = 256 / partCount;

        int ki = ipPart[startIndex] / eachPart;
        int sk = eachPart * ki;
        int ek = eachPart * (ki + 1) - 1;
        for (int i = 0; i < startIndex; i++) {
            startIP[i] = ipPart[i];
            endIP[i] = ipPart[i];
        }
        startIP[startIndex] = sk;
        endIP[startIndex] = ek;
        for (int i = startIndex + 1; i < startIP.length; i++) {
            startIP[i] = 0;
            endIP[i] = 255;
        }
    }

    public int[] getStartIPArr() {
        return startIP;
    }

    public int[] getEndIPArr() {
        return endIP;
    }

    public String getStartIPString() {
        return String.join(".", String.valueOf(startIP[0]), String.valueOf(startIP[1]), String.valueOf(startIP[2]),
            String.valueOf(startIP[3]));
    }

    public String getEndIPString() {
        return String.join(".", String.valueOf(endIP[0]), String.valueOf(endIP[1]), String.valueOf(endIP[2]),
            String.valueOf(endIP[3]));
    }

    public static void main(String[] args) throws Exception {
        SubnetUtil util = new SubnetUtil("0.0.0.0", 11);
        System.out.println("start: " + util.getStartIPString());
        System.out.println("end: " + util.getEndIPString());
    }

}
